/** 加载和解析html*/ 
import { fetchResource } from "../utils/fetchResource";
import { sandBox } from "../sandbox";
export const loadHtml = async (app) => {
    // 第一个子应用需要显示在哪里
    let container = app.container;   // 参见src/store/sub.js
    // 子应用入口
    let entry = app.entry

    const [dom, scripts] = await parseHtml(entry, app.name)
    const ct = document.querySelector(container)
    if(!ct) {
        throw new Error('容器不存在')
    }
    ct.innerHTML = dom;
    scripts.forEach(item => {
        sandBox(app, item)
        // 执行js脚本: 有2种方式
        // new Function(item).call(window, window)
        // eval(script)
    })
    
    return app
}

const cache = {} // 根据子应用的name来做缓存

export const parseHtml = async (entry, name) => {
    if (cache[name]) {
        return cache[name]
    }
    // 通过网络请求获取子应用内容: ajax请求网页地址获取HTML内容：http://localhost:9005/
    // 获取的只是文本内容，插入到页面后不会展示（js），需要解析
   const html =  await fetchResource(entry)
   
   // 解析：html中包含link、script 
   // 创建一个dom节点，通过dom节点来解析
    const div = document.createElement('div');
    div.innerHTML = html;
    
    // scriptURL: <script src="xxx"></script>
    // script: <script>xxx</script>
    const [dom, scriptUrl, script] = await getResources(div, entry)
    let allScript = []
    // 发送请求根据js的url获取js资源
    const fetchedScripts = await Promise.all(scriptUrl.map(async item => fetchResource(item)))
    allScript = script.concat(fetchedScripts)
    cache[name] = [dom, allScript]
   return [dom, allScript];
}

export const getResources = async (rootDom, entry) => {
    const scriptUrl = []
    const script = []
    const dom = rootDom.outerHTML
    
    function deepParse(element) {
        const children = element.children;
        const parent   = element.parent;
        // 处理script内容
        // 1、scriptURL: <script src="xxx"></script>
        // 2、script: <script>xxx</script>
        if(element.nodeName.toLowerCase() === 'script') {
            const src = element.getAttribute('src');
            if(!src) {
                script.push(element.outerHTML)
            }else {
                // 子应用静态资源引入是否带有域名或ip(publicPath是否设置会出现下面的情况)
                //  <script src="http://xxx"></script>
                // 暂不考虑https
                if(src.startsWith('http')) {
                    scriptUrl.push(src)
                }else {
                    //  <script src="/xxx/xx"></script>
                    scriptUrl.push(`http:${entry}/${src}`)
                }
            }
            
            // TODO: 为什么要替换？
            if(parent) {
                parent.replaceChild(document.createComment('此js文件已被微前端替换'), element)
            }
        }

        // link处理: link中也会有js内容
        // href="xx.js"
        if(element.nodeName.toLowerCase() === 'link') {
            const href = element.getAttribute('href');
            if(href.endsWith('.js')) {
                if(href.startsWith('http')) {
                    scriptUrl.push(href)
                }else {
                    //  <script src="/xxx/xx"></script>
                    scriptUrl.push(`http:${entry}/${href}`)
                }
            }
        }
        
        for(let i=0, len=children.length; i<len; i++) {
            deepParse(children[i])
        }
    }

    deepParse(rootDom)
    return [dom, scriptUrl, script]
}